\section{Desarrollo}

En esta sección se expone el desarrollo realizado para la implementación de este trabajo.

\subsection{Implementación de los Algoritmos}

Para la realización del presente trabajo se han implementado varios métodos para calcular ceros de funciones. Los algoritmos implementados son \textbf{Bisección}, \textbf{Newton} y \textbf{Secante}.

\subsubsection{Implementación del Método de Bisección}

La implementación del método de Bisección se realizó por varios motivos. Ante todo, es un método sencillo de implementar. Además, es un método muy confiable. El problema del método de Bisección es su velocidad. Así mismo, se pensó en utilizar el método de Bisección en combinación con otros métodos que son más eficientes pero son más sensibles al entorno de la raíz sobre el que son efectivos.

Como en la implementación de todos los métodos, se tuvo especial cuidado en evaluar la función la menor cantidad de veces posibles. Si bien el objetivo es que se evalúe la función una única vez para cada valor, eso no se ha asegurado. Sin embargo, se está muy cerca de ello con la implementación actual.

\subsubsection{Implementación del Método de la Secante}

El método de la Secante es un método de punto fijo que se caracteriza por utilizar la siguiente función de iteración:

$$x_{n+1} = g(x_{n}, x_{n-1}) = x_{n} - f(x_{n}) \frac{x_{n}-x_{n - 1}}{f(x_{n}-f(x_{n-1})}$$

\vspace{5mm}

Se puede traducir directamente esta función de iteración a código en C++ que resulta igualmente compacto y elegante. En C++ se puede escribir la función de iteración de la siguiente forma utilizando una característica del nuevo estándar C++, las funciones lambda:

\begin{verbatim}
[f](const Real &x, const Real &x_1) { return x-f(x) * (x-x_1) / (f(x)-f(x_1)); };
\end{verbatim}

Sin embargo, por más elegante que resulte escribir de esta manera la función de iteración, esta forma trae consigo dos problemas, uno que es aparente a simple vista y otro que resulta más difícil de observar. El problema más sencillo de descubrir es que la función de iteración así escrita evaluará la función $f$ más de una vez para el mismo valor de $x$. Además, existe otro problema de doble evaluación. Esto se debe a que para evaluar la función de iteración para un $x$, la función $f$ se evalúa tanto para el valor actual de $x$ como para el valor de su antecesor directo. Sin embargo, el valor de la función para el antecesor directo de $x$ ya fue calculado, y si se utiliza esta forma de escribir la función de iteración se evaluará innecesariamente la función $f$ en más de una oportunidad para el mismo valor. Es por este motivo que la función de iteración de la implementación del método de la Secante se ha escrito de la siguiente manera, y es el método el encargado de proveerle el valor de la función en el paso anterior:

\begin{verbatim}
const std::function< Real(Real, Real, Real, Real) > secant_function(
	[](const Real &x, const Real &x_1, const Real &fx, const Real &fx_1) {
			return x - fx * (x - x_1) / (fx - fx_1);
	}
);
\end{verbatim}

De esta manera, el método evaluará la función de iteración la menor cantidad de veces que sea necesaria. Esta optimización ha permitido reducir de 3 a 1 la cantidad de invocaciones sobre la función $f$ que se le pase al método. Esto es de suma importancia cuando el costo de calcular la función $f$ es elevado.

\subsubsection{Implementación del Método de Newton}

El método de Newton es un método de punto fijo que se caracteriza por utilizar la siguiente función de iteración:

$$x_{n+1} = g(x_{n}) = x_{n} - \frac{f(x_{n})}{f'(x_{n})}$$

\vspace{5mm}

La implementación de este método de punto fijo se basa en la implementación que se ha realizado de un método general de punto fijo que permite se escriba de manera muy sucinta. En este método no se observan los problemas que se observaron en la implementación del método de la Secante. Sin embargo, se debe tener en cuenta que si el costo de evaluar la derivada de la función $f$ es muy alto, la performance del método se puede ver afectada de manera negativa. Es por este motivo, que se realizó la optimización del cálculo de la función y la derivada de manera sucesiva para un mismo valor de $x$.
